// 学生接口
require("../models/relation")
require("./publicFn/asyncExits")

const init = require("../util/init")
const publicFnInit = require("./publicFn/init")
const Alipay = require("alipay-sdk")
const AlipayFormData = require("alipay-sdk/lib/form")
const moment = require("moment")
const {
    where
} = require("sequelize")
require('dotenv').config();

/**
 * 学生注册
 * @param {Object} stuObj 提交的属性
 * @param {string} stuObj.studentId 学号
 * @param {string} stuObj.Nickname 姓名
 * @param {string} stuObj.loginPwd 密码
 * @param {string} stuObj.phone 手机号
 * @param {string} stuObj.avatar 头像
 * @returns {Object} 创建成功的对象
 */
exports.register = async function (stuObj) {
    stuObj = init.pick(stuObj, "studentId", "Nickname", "loginPwd", "phone", "avatar") // 将需要的属性筛选，避免用户恶意传入值

    // 验证studentId是否在学号中
    init.validate.validators.studentIdExits = async function () {
        const result = await init.StudentID.findOne({
            where: {
                studentId: stuObj.studentId,
                studentName: stuObj.Nickname
            }
        })
        if (result) {
            return
        }
        return "is not exist" // 不存在
    }
    // 验证studentId是否存在学生信息表中
    init.validate.validators.studentInfoExits = async function () {
        const result = await init.StudentSInfon.findOne({
            where: {
                studentId: stuObj.studentId,
                Nickname: stuObj.Nickname
            }
        })
        if (!result) {
            return
        }
        return "is exist" // 存在
    }
    const rule = {
        // 验证规则
        studentId: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            studentInfoExits: true,
            studentIdExits: true
        },
        loginPwd: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            length: {
                minimum: 6,
                maximum: 10,
            }
        },
        Nickname: {
            presence: {
                allowEmpty: false
            },
            type: 'string'
        },
        phone: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            format: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
        },
        avatar: {
            type: "string"
        },
    }
    try {
        await init.validate.async(stuObj, rule)
    } catch (err) {
        throw {
            code: 401,
            err
        }
    }
    

        const classId = await init.StudentID.findOne({
            attributes: ["classInfoId"],
            where: {
                studentId: stuObj.studentId,
                studentName: stuObj.Nickname
            }
        })
        stuObj.loginPwd = init.md5(stuObj.loginPwd)
        stuObj.avatar = stuObj.avatar || "/upload/student.png"
        stuObj.classInfoId = classId.toJSON().classInfoId;
        const ins = await init.StudentSInfon.create(stuObj)
        return ins.toJSON()
   



}

/**
 * 学生登录
 * @param {Object} login 登录对象
 * @param {string}  login.studentId 学号
 * @param {string} login.loginPwd 密码
 * @returns 
 */
exports.login = async function (login) {
    login = init.pick(login, "studentId", "loginPwd")
    const rule = {
        studentId: {
            presence: {
                allowEmpty: false
            },
            type: "string"
        },
        loginPwd: {
            presence: {
                allowEmpty: false
            },
            type: "string"
        }
    }
    try {
        const reslut = init.validate(login, rule)
        if (reslut) {
            throw reslut
        }
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    const res = await init.StudentSInfon.findOne({
        attributes: ["id", "studentId"],
        where: {
            studentId: login.studentId,
            loginPwd: init.md5(login.loginPwd)
        }
    })

    if (!res) {
        return {
            state: 2,
            data: "登录失败"
        }
    }
    return res.toJSON()

}

/**
 * 入住
 * @param {Object} checkIn 提交对象
 * @param {Number} checkIn.bednumberId 床位id
 * @param {Number} checkIn.stuIofnId 学生id
 * @param {string} checkIn.OrderNo 订单号
 * @param {Number} checkIn.dormitoryId 宿舍楼id
 * @param {Number} checkIn.floorID 楼层id
 * @param {Number} checkIn.roomNoId 宿舍id
 * @returns {string} 入住成功
 */
exports.checkIn = async function (checkIn) {
    checkIn = init.pick(checkIn, "bednumberId", "stuIofnId", "OrderNo", "dormitoryId", "floorID", "roomNoId")

    // 验证床位id bednumberId 是否在床位表中并且是没有入住的
    init.validate.validators.bednumberIdExits = async function (value) {
        const res = await init.Bednumber.findOne({
            where: {
                [init.Op.and]: [{
                        id: value
                    },
                    {
                        isPeople: 0
                    }
                ]

            }
        })
        if (res) {
            return;
        } else {
            return "is Check In or absent"
        }
    }
    // 验证学生id stuIofnId 是否在学生信息表中并且没有床位id
    init.validate.validators.stuIofnIdExits = async function (value) {
        const res = await init.StudentSInfon.findOne({
            where: {
                [init.Op.and]: [{
                        id: value
                    },
                    {
                        BednumberId: null
                    }
                ]
            }
        })
        if (res) {
            return
        }
        return "is Check In or absent"
    }
    // 验证订单号
    init.validate.validators.OrderNoExits = async function (value) {
        const res = await init.StudentSInfon.findOne({
            where: {
                OrderNo: value
            }
        })
        if (!res) {
            return
        }
        return "is not Exits"
    }
    const rule = {
        bednumberId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            bednumberIdExits: true
        },
        stuIofnId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            stuIofnIdExits: true
        },
        OrderNo: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            OrderNoExits: true
        },
        dormitoryId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
        },
        floorID: {
            presence: {
                allowEmpty: false
            },
            type: "number",
        },
        roomNoId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
        }
    }
    try {
        await init.validate.async(checkIn, rule)
        // 验证宿舍楼id 楼层id 宿舍id 床位id 是否关联
        const idExits = await init.Bednumber.findOne({
            where: {
                RoomNoId: checkIn.roomNoId,
                id: checkIn.bednumberId
            },
            include: [{
                model: init.RoomNo,
                where: {
                    FloorId: checkIn.floorID
                },
                include: [{
                    model: init.Floor,
                    where: {
                        DormitoryId: checkIn.dormitoryId
                    },
                    include: [{
                        model: init.Dormitory,
                        where: {
                            id: checkIn.dormitoryId
                        }
                    }]
                }]
            }]
        })
        if (!idExits) {
            throw "Bednumber、Floor、RoomNoNo、Dormitory Not association"
        }
    } catch (err) {
        return {
            code: 401,
            err
        }
    }


        //修改学生信息表中的BednumberId(床位id) 和入住时间
        const res = await init.StudentSInfon.update({
            BednumberId: checkIn.bednumberId,
            checkInTime: +init.moment.utc(),
            EndTime: +init.moment.utc().add(12, "M"),
            OrderNo: checkIn.OrderNo
        }, {
            where: {
                id: checkIn.stuIofnId
            }
        })
        const update = await init.updataToStay({
            roomNoId: checkIn.roomNoId,
            floorID: checkIn.floorID,
            dormitoryId: checkIn.dormitoryId,
            bednumberId: checkIn.bednumberId
        }, true)
        const reslut = {
            res,
            ...update
        }

        let isRes = true
        let err = {}
        for (let key in reslut) {
            if (reslut[key][0] === 0) {
                isRes = false
                err.err[key] = reslut[key][0]
            }
        }
        if (isRes) {
            return "入住成功"
        }
        return {
            code: 401,
            err
        }
    
}


/**
 * 起床打卡
 * @param {*} id 学生id
 */
exports.getUp = async function (id) {
    const TIME_REQUIRE = "08:00:00" // 规定的起床时间
    const limitTime = "06:00:00" // 限制什么时候打卡
    try {
            const reslut = await init.StudentRecords(limitTime, id, async function (current) {
                // 判段是否是同一天打卡
                const desc = await init.Getup.findAll({
                    attributes: ["time"],
                    order: [
                        ['time', 'DESC']
                    ],
                    where: {
                        StudentSInfonId: id,
                        isGetUp: {
                            [init.Op.not]: -1
                        }
                    },
                    limit: 1
                })
                // 计算是否是同一天
                let isSameDay = 1
                if (JSON.parse(JSON.stringify(desc))[0]) {
                    isSameDay = init.moment(init.moment(JSON.parse(JSON.stringify(desc))[0].time).local().format("YYYY-MM-DD")).diff(current, "days")
                }
                if (isSameDay === 0) {
                    throw "Cannot clock in again on the same day"
                }
                const diff = init.moment(current.split(" ")[1], "HH:mm:ss").diff(init.moment(TIME_REQUIRE, "HH:mm:ss"), "seconds") // 获取是否按规定时间起床
                const res = await init.Getup.update({
                    isGetup: diff < 0
                }, {
                    where: {
                        StudentSInfonId: id,
                        time: {
                            [init.Op.between]: [init.moment().startOf('day').format('x'), init.moment().endOf('day').format('x')]
                        }
                    }
                })
                return res[0] ? {
                    isPass: diff < 0,
                    text: "打卡成功"
                } : ""
            })
            return reslut
        
    } catch (err) {
        return {
            code: 401,
            err
        }
    }

}


/**
 * 归宿打卡
 * @param {*} id 学生id
 * 
 */

exports.Returns = async function (id) {
    const TIME_REQUIRE = "21:00:00" // 规定的归宿时间
    const limitTime = "17:00:00" // 限制什么时候打卡
    try {
        
            const reslut = await init.StudentRecords(limitTime, id, async function (current) {
                // 判段是否是同一天打卡 
                const desc = await init.Destination.findAll({
                    attributes: ["time"],
                    order: [
                        ['time', 'DESC']
                    ],
                    where: {
                        StudentSInfonId: id,
                        isDestination: {
                            [init.Op.not]: -1
                        }
                    },
                    limit: 1
                })
                // 计算是否是同一天
                let isSameDay = 1
                if (JSON.parse(JSON.stringify(desc))[0]) {
                    isSameDay = init.moment(init.moment(JSON.parse(JSON.stringify(desc))[0].time).local().format("YYYY-MM-DD")).diff(current, "days")
                }
                if (isSameDay === 0) {
                    throw "Cannot clock in again on the same day"
                }

                const diff = init.moment(current.split(" ")[1], "HH:mm:ss").diff(init.moment(TIME_REQUIRE, "HH:mm:ss"), "seconds") // 获取是否按规定时间归宿
                const res = await init.Destination.update({
                    isDestination: diff < 0
                }, {
                    where: {
                        StudentSInfonId: id,
                        time: {
                            [init.Op.between]: [init.moment().startOf('day').format('x'), init.moment().endOf('day').format('x')]
                        }
                    }
                })
                return res[0] ? {
                    isPass: diff < 0,
                    text: "打卡成功"
                } : ""
            })
            return reslut

        

    } catch (err) {
        return {
            code: 401,
            err
        }
    }
}

/**
 * 打扫登记
 * @param {*} id 学生id
 */
exports.clean = async function (id) {
    const limitTime = "00:00:00" // 规定什么时候开签到
    try {
       
            const reslut = await init.StudentRecords(limitTime, id, async function (current) {
                // 判段是否是同一天打卡 
                const desc = await init.Clean.findAll({
                    attributes: ["time"],
                    order: [
                        ['time', 'DESC']
                    ],
                    where: {
                        StudentSInfonId: id
                    },
                    limit: 1
                })
                // 计算是否是同一天
                let isSameDay = 1
                if (JSON.parse(JSON.stringify(desc))[0]) {
                    isSameDay = init.moment(init.moment(JSON.parse(JSON.stringify(desc))[0].time).local().format("YYYY-MM-DD")).diff(current, "days")
                }
                if (isSameDay === 0) {
                    throw "Cannot clock in again on the same day"
                }
                const obj = {
                    time: +init.moment.utc(),
                    StudentSInfonId: id
                }
                const res = await init.Clean.create(obj)
                return res.toJSON()
            })
            return reslut


    } catch (err) {
        return {
            code: 401,
            err
        }
    }
}

/**
 * 获取是否今日是否打卡
 * @param {number} id 学生id
 * @param {number} obtainWho 1:起床 2:归宿 3:打扫
 */
exports.getIsSignIn = async (id, obtainWho) => {
    const sizes = [1, 2, 3];
    const rule = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number"
        },
        obtainWho: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            inclusion: sizes
        },

    }
    try {
        const Exits = init.validate({
            id,
            obtainWho
        }, rule)
        if (Exits) {
            throw Exits
        }
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    let isSignIn = true
    let res = null
    switch (obtainWho) {
        case 1:
            res = await init.Getup.findOne({
                where: {
                    StudentSInfonId: id,
                    time: {
                        [init.Op.between]: [init.moment().startOf('day').format('x'), init.moment().endOf('day').format('x')]
                    },
                    isGetUp: -1
                }
            })
            if (res) {
                isSignIn = false
            }
            break;

        case 2:
            res = await init.Destination.findOne({
                where: {
                    StudentSInfonId: id,
                    time: {
                        [init.Op.between]: [init.moment().startOf('day').format('x'), init.moment().endOf('day').format('x')]
                    },
                    isDestination: -1
                }
            })
            if (res) {
                isSignIn = false
            }
            break;
        case 3:
            res = await init.Clean.findOne({
                where: {
                    StudentSInfonId: id,
                    time: {
                        [init.Op.between]: [init.moment().startOf('day').format('x'), init.moment().endOf('day').format('x')]
                    }
                }
            })
            if (!res) {
                isSignIn = false
            }
            break
    }
    return {
        obtainWho,
        isSignIn
    }

}
/**
 * 获取打卡记录
 * @param {object} data 提供的数据对象
 * @param {number} data.id 用户id 必填
 * @param {number} data.obtainWho 1:起床 2:归宿 3:打扫
 * @param {number} data.page 页码
 * @param {number} data.limit 每页多少条数据
 * @param {string} data.startingTime 起始时间
 * @param {string} data.endTime 终止时间
 * @returns 
 */
exports.getCheckInRecords = async (data) => {
    const sizes = [1, 2, 3];
    const rule = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number"
        },
        obtainWho: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            inclusion: sizes
        },
        page: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            numericality: {
                onlyInteger: true,
                greaterThan: 0,
            }
        },
        limit: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            numericality: {
                onlyInteger: true,
                greaterThan: 0,
            }
        },
        startingTime: {
            type: "string",
        },
        endTime: {
            type: "string",
        }
    }
    try {
        const Exits = init.validate(data, rule)
        if (Exits) {
            throw Exits
        }
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    // 得到obtainWho对应的条件，该用户的全部数据
    let res = null;
    switch (data.obtainWho) {
        case 1:
            res = await init.Getup.findAll({
                attributes: ["id", "time", ["isGetup", "CheckInStatus"]],
                where: {
                    StudentSInfonId: data.id
                }
            })
            break;
        case 2:
            res = await init.Destination.findAll({
                attributes: ["id", "time", ["isDestination", "CheckInStatus"]],
                where: {
                    StudentSInfonId: data.id
                }
            })
            break;
        case 3:
            res = await init.Clean.findAll({
                where: {
                    StudentSInfonId: data.id
                }
            })
            break;
    }

    const reslut = await publicFnInit.RecordViewing({
        page: data.page,
        limit: data.limit,
        conditionObj: {
            studentId: data.id,
            startingTime: data.startingTime || "",
            endTime: data.endTime || String(moment().endOf('day').format('x'))
        }
    }, async function (where) {
        let info = null;
        switch (data.obtainWho) {
            case 1:
                info = await init.Getup.findAndCountAll({
                    attributes: ['id', 'time', ['isGetup', 'CheckInStatus']],
                    offset: (data.page - 1) * data.limit,
                    limit: data.limit,
                    where,
                    include: [{
                        model: init.StudentSInfon,
                        attributes: ["id", "Nickname", "studentId", "checkInTime"]
                    }]
                })
                break;
            case 2:
                info = await init.Destination.findAndCountAll({
                    attributes: ['id', 'time', ['isDestination', 'CheckInStatus']],
                    offset: (data.page - 1) * data.limit,
                    limit: data.limit,
                    where,
                    include: [{
                        model: init.StudentSInfon,
                        attributes: ["id", "Nickname", "studentId", "checkInTime"]
                    }]
                })
                break;
            case 3:
                info = await init.Clean.findAndCountAll({
                    offset: (data.page - 1) * data.limit,
                    limit: data.limit,
                    where,
                    include: [{
                        model: init.StudentSInfon,
                        attributes: ["id", "Nickname", "studentId", "checkInTime"]
                    }]
                })
                break;
        }
        if (JSON.parse(JSON.stringify(info)).rows.length === 0) {
            return {
                code: 401,
                err: "There's no data left"
            }
        }
        const percentage = publicFnInit.percentage(JSON.parse(JSON.stringify(info)).rows[0].StudentSInfon.checkInTime, JSON.parse(JSON.stringify(res)), "CheckInStatus")
        return {
            total: JSON.parse(JSON.stringify(info)).count,
            percentage,
            rows: JSON.parse(JSON.stringify(info)).rows
        }
    })
    return reslut;

}



/**
 * 获取学生个人信息
 * @param {*} id 学生id
 */
exports.Information = async function (id) {

    const StuInfo = await init.StudentSInfon.findByPk(id, {
        attributes: ["id", "studentId", "Nickname", "phone", "avatar", "checkInTime", "BednumberId", "EndTime"],
        include: [{
            model: init.classInfo
        }]
    })
    if (!StuInfo) {
        return {
            code: 401,
            err: "id is absent"
        }
    }
    const JSONStuInfo = StuInfo.toJSON()
    let Info = {
        id: JSONStuInfo.id,
        studentId: JSONStuInfo.studentId,
        Nickname: JSONStuInfo.Nickname,
        phone: JSONStuInfo.phone,
        avatar: JSONStuInfo.avatar,
        checkInTime: JSONStuInfo.checkInTime,
        BednumberId: JSONStuInfo.BednumberId,
        EndTime: JSONStuInfo.EndTime,
        classId: JSONStuInfo.classInfo.id,
        className: JSONStuInfo.classInfo.className
    }
    const roomObj = await init.Bednumber.findByPk(Info.BednumberId, {
        include: [{
            model: init.RoomNo,
            include: [{
                model: init.Floor,
                include: [{
                    model: init.Dormitory
                }]
            }]
        }]
    })

    let res = null
    if (roomObj) {
        res = roomObj.toJSON()
    }
    Info.bednumber = res ? res.bednumberId : null
    Info.roomNoId = res ? res.RoomNo.id : null
    Info.roomNo = res ? res.RoomNo.roomNo : null
    Info.floorID = res ? res.RoomNo.Floor.id : null
    Info.floorNumber = res ? res.RoomNo.Floor.floorNumber : null
    Info.dormitoryId = res ? res.RoomNo.Floor.Dormitory.id : null
    Info.dormitoryName = res ? res.RoomNo.Floor.Dormitory.DormitoryName : null
    return Info;

}

/**
 * 修改学生个人信息
 * @param {Object} Stu
 * @param {number} Stu.id 学生id
 * @param {string} Stu.studentAvatar 学生头像
 * @param {string} Stu.phone 学生手机号
 */
exports.modifyInfo = async function (Stu) {
    Stu = init.pick(Stu, "id", "studentAvatar", "phone")
    const rule = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number"
        },
        studentAvatar: {
            type: "string"
        },
        phone: {
            type: "string",
            format: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
        }
    }
    try {

    } catch (err) {
        let Exits = init.validate(Stu, rule)
        if (Exits) {
            throw Exits
        }
        return {
            code: 401,
            err
        }
    }
    

        let obj = {}
        if (Stu.studentAvatar) {
            obj.avatar = Stu.studentAvatar
        }
        if (Stu.phone) {
            obj.phone = Stu.phone
        }
        const res = await init.StudentSInfon.update({
            ...obj
        }, {
            where: {
                id: Stu.id
            }
        })
        if (res[0]) {
            return {
                text: "修改完成"
            }
        } else {
            throw "Add at least one data"
        }
    





}

/**
 * 找回密码
 * @param {Object} Stu
 * @param {*} Stu.studentId 学号
 * @param {*} Stu.Nickname 姓名
 * @param {*} Stu.newLoginPwd 新密码
 */
exports.find = async function (Stu) {
    Stu = init.pick(Stu, "studentId", "Nickname", "newLoginPwd")
    init.validate.validators.newLoginPwdExits = async function (value) {
        const res = await init.StudentSInfon.findOne({
            where: {
                studentId: Stu.studentId,
                Nickname: Stu.Nickname,
                loginPwd: init.md5(value)
            }
        })
        if (!res) {
            return
        }
        return "Cannot be repeated"
    }
    const rule = {
        studentId: {
            presence: {
                allowEmpty: false
            },
            type: "string"
        },
        Nickname: {
            presence: {
                allowEmpty: false
            },
            type: "string"
        },
        newLoginPwd: {
            presence: {
                allowEmpty: false
            },
            newLoginPwdExits: true,
            type: "string",
            length: {
                minimum: 6,
                maximum: 10,
            }
        }
    }
    try {
        await init.validate.async(Stu, rule)
    } catch (err) {

        return {
            code: 401,
            err
        }
    }
   

        const res = await init.StudentSInfon.update({
            loginPwd: init.md5(Stu.newLoginPwd)
        }, {
            where: {
                studentId: Stu.studentId,
                Nickname: Stu.Nickname
            }
        })
        if (!res[0]) {
            throw {
                code: 401,
                err: "studentId or Nickname absent"
            }
        }
        return "修改成功"
   

}

/**
 * 学生入住支付宝支付功能
 * @param {Object} ctx 商品数据
 * @param {string} ctx.subject 商品详情
 * @param {number} ctx.payMoney 价格
 * @param {number} ctx.peopleNum 几人间
 * @param {number} ctx.roomNoId 房间号id
 * @param {number} ctx.bednumberId 床号id
 * @param {number} id 用户id
 * @returns 付款二维码和订单号
 * 
 */
exports.payment = async function (ctx, id) {
    ctx = init.pick(ctx, "subject", "payMoney", "peopleNum", "roomNoId")
    console.log(ctx);
    // 验证商品价格
    init.validate.validators.roomrateExits = async function () {
        const res = await init.RoomRate.findOne({
            where: {
                price: ctx.payMoney,
                peopleNum: ctx.peopleNum
            }
        })
        if (res) {
            return
        }
        return "is not Exits"
    }
    // 验证一共房间中有几个床位号
    init.validate.validators.bednumberExists = async function (value) {
        const RoomNoId = await init.Bednumber.findOne({
            where: {
                id: value,
                // isPeople: 0
            },
            attributes: ["RoomNoId"]
        })
        if (!RoomNoId) {
            return "is not Exits"
        }
        const count = await init.Bednumber.count({
            where: {
                RoomNoId: RoomNoId.toJSON().RoomNoId,
            }
        })
        if (count === ctx.peopleNum) {
            return
        }
        return "Wrong parameters"

    }
    // 验证ctx对象
    const ralu = {
        subject: {
            presence: {
                allowEmpty: false
            },
            type: "string"
        },

        payMoney: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            roomrateExits: true
        },
        roomNoId: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            bednumberExists: true,
        }
    }
    // 验证学生id是否存在并且没有入住
    init.validate.validators.idExits = async function (value) {
        const res = await init.StudentSInfon.findOne({
            where: {
                id: value,
                BednumberId: {
                    [init.Op.is]: null
                }
            }
        })

        if (res) {
            return
        }
        return "Wrong parameters"
    }
    // 验证id
    const raluId = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            idExits: true
        }
    }
    try {
        // 验证ctx对象
        await init.validate.async(ctx, ralu)
        // 验证id
        await init.validate.async({
            id
        }, raluId)
    } catch (err) {
        return {
            code: 401,
            err
        }
    }
    
        const Order = Date.now().toString()
        // 支付
        const alipay = new Alipay({
            appId: process.env.APPID,
            privateKey: process.env.PRIVATEKEY,
            alipayPublicKey: process.env.ALIPAYPUBLICKEY,
            gateway: process.env.GATEWAY,
        })
        const formData = new AlipayFormData();
        formData.setMethod('get');
        formData.addField('bizContent', {
            outTradeNo: Order, // 支付商品编号12
            productCode: 'FAST_INSTANT_TRADE_PAY', // 销售的产品码
            totalAmount: (+ctx.payMoney).toFixed(2),
            qr_pay_mode: 4,
            qrcode_width: 100,
            subject: ctx.subject,
            time_expire: moment(moment().add(100, "s")).format("yyyy-MM-DD HH:mm:ss"),
        });
        const resulet = await alipay.exec(
            'alipay.trade.page.pay', {}, {
                formData
            }
        )
        return {
            resulet,
            Order
        }
    
}








/**
 * 修改密码
 * @param {Object} Stu 用户提交数据
 * @param {number} Stu.id 用户id
 * @param {string} Stu.newLoginPwd 新密码
 * @param {string} Stu.confirmLoginPwd 确认密码
 * @param {string} Stu.oldLoginPwd 旧密码
 */
exports.updataLoginPwd = async function (Stu) {
    Stu = init.pick(Stu, "id", "newLoginPwd", "confirmLoginPwd", "oldLoginPwd")
    const rule = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number",
        },
        newLoginPwd: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            length: {
                minimum: 6,
                maximum: 10,
            },
            equality: "confirmLoginPwd"
        },
        confirmLoginPwd: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            length: {
                minimum: 6,
                maximum: 10,
            },
        },
        oldLoginPwd: {
            presence: {
                allowEmpty: false
            },
            type: "string",
            length: {
                minimum: 6,
                maximum: 10,
            },
        }
    }

    try {} catch (err) {
        const Exits = init.validate(Stu, rule);
        if (Exits) {
            throw Exits
        }
        if (Stu.oldLoginPwd === Stu.newLoginPwd) {
            throw "The new and old passwords cannot be the same"
        }
        return {
            code: 401,
            err
        }
    }
   
        const isRes = await init.StudentSInfon.findOne({
            where: {
                id: Stu.id,
                loginPwd: init.md5(Stu.oldLoginPwd)
            }
        })
        if (!isRes) {
            return {
                state: 2,
                text: "旧密码有问题"
            }
        }
        const res = await init.StudentSInfon.update({
            loginPwd: init.md5(Stu.newLoginPwd)
        }, {
            where: {
                id: Stu.id
            }
        })
        if (res[0]) {
            return {
                state: 1,
                text: "修改成功"
            }
        } else {
            return {
                coed: 401,
                err: "Modification failed"
            }
        }
   

}

/**
 * 获取可以选择的宿舍
 * @param {number} id 班级id
 */
exports.getRoomScope = async function (id) {
    const rule = {
        id: {
            presence: {
                allowEmpty: false
            },
            type: "number",
            stuIdExits: true
        },
    }
    try {
        await init.validate.async({
            id
        }, rule)
    } catch (err) {
        console.log(err);
        return {
            code: 401,
            err
        }
    }
    

        const res = await init.RoomNo.findAll({
            attributes: ["id", "roomNo", "roomResided", "roomCapacity"],
            where: {
                classInfoId: id
            },
            include: [{
                    attributes: ["id", "className"],
                    model: init.classInfo,
                },
                {

                    attributes: ["id", "floorNumber"],
                    model: init.Floor,
                    include: [{
                        attributes: ["id", "DormitoryName"],
                        model: init.Dormitory
                    }]

                }
            ]
        })
        const reslut = [];
        JSON.parse(JSON.stringify(res)).forEach(item => {
            reslut.push({
                id: item.id,
                roomNo: item.roomNo,
                roomCapacity: item.roomCapacity,
                roomResided: item.roomResided,
                classInfo: {
                    id: item.classInfo.id,
                    className: item.classInfo.className
                },
                Floor: {
                    id: item.Floor.id,
                    floorNumber: item.Floor.floorNumber
                },
                Dormitory: {
                    id: item.Floor.Dormitory.id,
                    DormitoryName: item.Floor.Dormitory.DormitoryName
                }
            })
        })
        return reslut
   


}

/**
 * 报修
 * @param {number} RoomId 宿舍id
 * @param {String} RepairDescription 报修描述
 * @param {String} RepairImg 报修图片
 * @param {string} RepariDormitroy 报修宿舍楼
 * @param {string} RepariFloor 报修楼层
 * @param {string} RepariRoomNo 报修房间
 */
exports.RepairReport = async function (RepairObj) {
    RepairObj = init.pick(RepairObj,"RoomId","describe","avatar","RepariDormitroy","RepariFloor","RepariRoomNo")
    const rule = {
        RoomId:{
            presence: {
                allowEmpty: false
            },
            type: "number",
            RoomNoExits: true,
        },
        describe:{
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        avatar:{
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        RepariDormitroy:{
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        RepariFloor:{
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        RepariRoomNo:{
            presence: {
                allowEmpty: false
            },
            type: "string",
        }
    }
    try{
        await init.validate.async(RepairObj,rule)
    }catch(err){
        return {
            code: 401,
            err
        }
    }
   
        const dataObj = {
            RepairDescription: RepairObj.describe,
            RepairImg: RepairObj.avatar,
            RepairStartTime: +init.moment.utc(),
            RoomNoId: RepairObj.RoomId,
            RepariDormitroy: RepairObj.RepariDormitroy,
            RepariFloor: RepairObj.RepariFloor,
            RepariRoomNo: RepairObj.RepariRoomNo
        }
        const res = await init.RepairReport.create(dataObj);
        if(Object.keys(res.toJSON()).length !== 0){
            return "报修成功"
        }
  
}